iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0
Modern Web

30 days of React 系列 第 7

Day 7 - 條件式渲染 (Conditional Rendering)

  • 分享至 

  • xImage
  •  

條件式渲染(conditional rendering) 讓我們能夠在特定的條件來動態地渲染不同的元件或內容。譬如在JavaScript 學習過的的 if… else… statement , ternary operator, 或&& 的邏輯運算子 等,都可以用來操作條件式渲染,這些也可以說是學習條件式渲染的必備知識。本篇會我們來看看三種條件式渲染的例子。

假設我們有一個電影的觀看清單長這樣:

週末電影清單

  • 令人討厭的松子的一生✔️
  • 鬥陣俱樂部✔️
  • 猜火車

若該影片已經看完了,就打「✔️ 」若還沒看就保持空白。分別用if 陳述式、我們可以怎麼做呢?

透過if 陳述式

function Item({ name, isWatched }) {
  let itemContent = name;
  if (isWatched) {
    itemContent = name + "✔️ ";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function WatchingListList() {
  return (
    <section>
      <h1>週末電影清單</h1>
      <ul>
        <Item
          isWatched={true}
          name="令人討厭的松子的一生"
        />
        <Item
          isWatched={true}
          name="鬥陣俱樂部"
        />
        <Item
          isWatched={false}
          name="猜火車"
        />
      </ul>
    </section>
  );
}

React 的條件式渲染原則上跟JavaScript所學的條件式邏輯的寫法相當。我們將電影名稱另外於頂部宣告為變數,若「已觀看狀態」(isWatched) 為真,則在電影名稱後方加上✔️。下方的WatchingList 元件的操作,就跟我們先前在props的篇章所學過的編輯內容相同,編輯相對應的電影資訊即可。

這個方法需要留意的是,變數需要宣告在最上方,而不能連同 return 裡頭的 JSX一起放置,因為JSX只能接受表達式。(這部分看JSX的介紹篇章)

小補充:若是這串code使用原生去寫會長怎樣呢:

function Item({ name, isWatched }) {
  let itemContent = name;
  if (isWatched) {
    itemContent = name + "✔️ ";
  }
  return React.createElement(
    "li",
    { className: "item" },
    itemContent
  );
}

function WatchingList() {
  return React.createElement(
    "section",
    null,
    React.createElement("h1", null, "週末電影清單"),
    React.createElement(
      "ul",
      null,
      React.createElement(Item, {
        isWatched: true,
        name: "令人討厭的松子的一生",
      }),
      React.createElement(Item, {
        isWatched: true,
        name: "鬥陣俱樂部",
      }),
      React.createElement(Item, {
        isWatched: false,
        name: "猜火車",
      })
    )
  );
}

export default WatchingList;

透過&& 運算式

function Item({ name, isWatched }) {
  return (
    <li className="item">
      {name} {isWatched && '✔'}
    </li>
  );
}

export default function WatchingList() {
  return (
    <section>
      <h1>週末電影清單</h1>
      <ul>
        <Item
          isWatched={true}
          name="令人討厭的松子的一生"
        />
        <Item
          isWatched={true}
          name="鬥陣俱樂部"
        />
        <Item
          isWatched={false}
          name="猜火車"
        />
      </ul>
    </section>
  );
}

這裡我們使用的是&& 運算式來處理,根據條件的真偽來決定是否顯示特定的內容。如果 isWatched 是真(true),則會渲染 '✔',如果 isWatched 是假(false),則不會渲染 '✔'

透過三元運算子

return (
  <li className="item">
    {isWatched ? name + ' ✔' : name}
  </li>
);

三元運算子也是表達式,所以也可以一併寫在JSX 當中。

電影資料卡

假設我們想做一個電影資料卡,讓使用者能夠透過片名顯示相對應的資訊,呈現出電影資料卡片的元件。原始的資料假設是這樣:

令人討厭的松子的一生 鬥陣俱樂部 猜火車
年份 2006年 1999 年 1996 年
片長 2 小時 10 分鐘 2 小時 19 分鐘 1 小時 34 分鐘
導演 中島哲也 大衛·芬奇 丹尼·鮑伊

第一個作法:

function Movie({ name }) {
  let year, minutes, director;
  if (name === '令人討厭的松子的一生') {
    year = '2006年';
    minutes = '2 小時 10 分鐘';
    director = '中島哲也';
  } else if (name === '鬥陣俱樂部') {
    year = '1999 年';
    minutes = '2 小時 19 分鐘';
    director = '大衛·芬奇';
  } else if (name === '猜火車') {
    year = '1999 年';
    minutes = '1 小時 34 分鐘';
    director = '丹尼·鮑伊';
  }
  return (
    <section>
      <h1>{name}</h1>
      <dl>
        <dt>年份</dt>
        <dd>{year}</dd>
        <dt>片長</dt>
        <dd>{minutes}</dd>
        <dt>導演</dt>
        <dd>{director}</dd>
      </dl>
    </section>
  );
}

export default function MovieList() {
  return (
    <div>
      <Movie name="令人討厭的松子的一生" />
      <Movie name="鬥陣俱樂部" />
      <Movie name="猜火車" />
    </div>
  );
}

做出來長這樣,其他二部片同結果,這邊就不截圖了。

這個的做法維持原始的props,並將year, minutes, director的邏輯寫在if 的句子裡。在這個步驟中year, minutes, director定義出來。再來,在return 中返回JSX樹的結構,並也在當中使用的 year, minutes, director的變數。

但若是今天想追加一部電影的話,可能操作起來就會比較繁複,我們可以試試以下的方法。

方法二:

const movies = {
  令人討厭的松子的一生: {
    year: '2006年',
    minutes: '2 小時 10 分鐘',
    director: '中島哲也'
  },
  鬥陣俱樂部: {
    year: '1999 年',
    minutes: '2 小時 19 分鐘',
    director: '大衛·芬奇'
  },
  猜火車: {
    year: '1999 年',
    minutes: '1 小時 34 分鐘',
    director: '丹尼·鮑伊'
  },
};

function Movie({ name }) {
  const info = movies[name];

  return (
    <section>
      <h1>{name}</h1>
      <dl>
        <div>
          <dt>年份</dt>
          <dd>{info.year}</dd>
        </div>
        <div>
          <dt>片長</dt>
          <dd>{info.minutes}</dd>
        </div>
        <div>
          <dt>導演</dt>
          <dd>{info.director}</dd>
        </div>
      </dl>
    </section>
  );
}

export default function MovieList() {
  return (
    <div>
      <Movie name="令人討厭的松子的一生" />
      <Movie name="鬥陣俱樂部" />
      <Movie name="猜火車" />
    </div>
  );
}

第二個作法首先將電影的相關資訊分別儲存在objects當中,並宣告為變數movies。再來,在Movies元件當中另外定義出info 變數的內容,也就是movies object裡的keys,再來在return 當中建立JSX的結構,變數方法使用引入object的key來指定類別。

這個作法的優勢是,可以輕易地增加,而不需變動Movie的元件設定。僅需在movies的變數中添加品項以及修改MovieList的結構即可。

當今天我們要新增一部電影資訊時,我們僅需要新增以下:

  日麗: {
    year: '2023 年',
    minutes: '1 小時 36 分鐘',
    director: '夏洛特·威爾斯'
  },
<Movie name="日麗" />

至於如何做到不改動MovieList的元件結構,自動渲染資料,我們後續再談。

參考資料

  1. React 官方文件 - Conditional Rendering
  2. The Joy of React by Josh W Comeau

上一篇
Day 6 - 傳遞Props
下一篇
Day 8 - 渲染清單
系列文
30 days of React 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言